﻿/*
 *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the License); you may
 *  not use this file except in compliance with the License.
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 */

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <gmssl/sm2.h>
#include <gmssl/sm4.h>
#include <gmssl/rand.h>
#include <gmssl/x509_cer.h>
#include <gmssl/x509_req.h>
#include <gmssl/pem.h>
#include <gmssl/asn1.h>
#include <gmssl/cms.h>
#include <gmssl/error.h>
#include "base64.h"

#define BUFFER_SIZE 4096

 /*
 *   加载证书数据
 * @param cert_file: 证书文件
 * @param cert_data: 证书数据
 * @param cert_data_len: 证书数据长度
 * @param maxlen: 证书数据最大长度
 */
static int load_x509_cert_from_pem(const char* cert_file, uint8_t* cert_data, uint8_t* cert_data_len, size_t maxlen) {
    int ret;
    FILE* fp = fopen(cert_file, "r");
    if (!fp) {
        fprintf(stderr, "打开加密证书文件失败...\n");
        return 0;
    }

    ret = x509_cert_from_pem(cert_data, cert_data_len, maxlen, fp);
    if (ret != 1) {
        fprintf(stderr, "加密证书转成der格式失败\n");
        fclose(fp);
        return 0;
    }
    fclose(fp);

    return 1;
}

/**
* 解析私钥证书私钥数据
* @param key_file 私钥证书路径
* @param privateKey 私钥数据
*/
static int parse_key_pem(const char* key_file, uint8_t* privateKey) {
    FILE * fp = NULL;
    int ret = 0;
    long der_data_len = 0;
    char der_data[1024] = { 0 };
    char key_der_base64_data[1024] = { 0 };
    char key_der_base64_temp[1024] = { 0 };
    size_t key_der_data_base64_len = 0;
    
    char der_data_copy[1024] = { 0 };
    char start_char[28] = "-----BEGIN PRIVATE KEY-----";
    char line_data[28] = { 0 };

    uint8_t* key_der_data = NULL;
    size_t key_der_data_len = 0;
    size_t i = 0, j = 0;

    fp = fopen(key_file, "r");
    if (!fp) {
        return 0;
    }

    fseek(fp, 0, SEEK_END);
    der_data_len = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    if (der_data_len > sizeof(der_data)) {
        return 0;
    }

    fread(der_data, 1, sizeof(der_data), fp);
    fclose(fp);

    strncpy(der_data_copy, der_data, der_data_len);

    char* line = strtok(der_data_copy, "\n");
    strncpy(line_data, line, 27);
    if (strcmp(line_data, line) != 0) {
        return 0;
    }

    while (der_data[i] != '\0' && j < sizeof(key_der_base64_temp) - 1) {
        if (der_data[i] != '\n' && der_data[i] != '\r') {
            key_der_base64_temp[j] = der_data[i];
            j++;
        }
        i++;
    }

    strncpy(key_der_base64_data, key_der_base64_temp + 27, strlen(key_der_base64_temp) - 27 - 25);

   key_der_data = base64_decode((const char *)key_der_base64_data, strlen(key_der_base64_temp) - 27 - 25, &key_der_data_len);
   if (!key_der_data) {
       fprintf(stderr, "解析base64失败\n");
       return 0;
   }

   for (size_t i = 0; i < key_der_data_len; i++) {
       printf("%02x ", key_der_data[i]);
   }
   printf("\n");
  
   for (i = 0; i < key_der_data_len; i++) {
       if (key_der_data[i] == 0x04 && key_der_data[i + 1] == 0x20) {
           i += 2;
           break;
       }
   }

   memcpy(privateKey, key_der_data + i, 32);
   printf("私钥数据如下: \n");
   for (size_t k = 0; k < 32; k++) {
       printf("%02x ", privateKey[k]);
   }
   printf("\n");

   return 1;
}

 /*
 *  生成SM2密钥对
 * @param key_file: 密钥对文件路径
 * @param 私钥密码
 *
 */
static int generate_sm2_keypai(const char* key_file, const char* pass) {
    int ret = 0;
    FILE* fp = NULL;
    SM2_KEY	key;


    printf("生成密钥对...\n");
    ret = sm2_key_generate(&key);
    if (ret != 1) {
        fprintf(stderr, "SM2密钥对生成失败\n");
        return 0;
    }

    printf("生成密钥对成功...");

    fp = fopen(key_file, "wb");
    if (!fp) {
        fprintf(stderr, "无法创建文件: %s\n", key_file);
        return 0;
    }

    // 使用密码加密私钥
    printf("使用密码加密私钥...\n");
    ret = sm2_private_key_info_encrypt_to_pem(&key, pass, fp);
    if (ret != 1) {
        fprintf(stderr, "保存加密私钥失败\n");
        fclose(fp);
        return 0;
    }
    printf("加密私钥已保存到: %s\n", key_file);
    fclose(fp);

    printf("\n=== SM2密钥对信息 ===\n");
    // 显示私钥（前16字节，出于安全考虑不显示完整私钥）
    printf("私钥: ");
    for (int i = 0; i < 32; i++) {
        printf("%02x", key.private_key[i]);
    }
    printf("\n");

    // 显示公钥
    printf("公钥X坐标: ");
    for (int i = 0; i < 32; i++) {
        printf("%02x", key.public_key.x[i]);
    }
    printf("\n");

    printf("公钥Y坐标: ");
    for (int i = 0; i < 32; i++) {
        printf("%02x", key.public_key.y[i]);
    }
    printf("\n");

    return 1;
}

/*
    加载私钥
    @param key_file: 私钥文件路径
    @param pass: 密码
    @param key: 输出的私钥
*/
static int load_sm2_private_key(const char* key_file, const char* pass, SM2_KEY* key) {
    FILE* fp = fopen(key_file, "r");
    if (!fp) {
        fprintf(stderr, "无法打开密钥文件: %s\n", key_file);
        return 0;
    }

    int ret = sm2_private_key_info_decrypt_from_pem(key, pass, fp);
    fclose(fp);
    if (ret != 1) {
        fprintf(stderr, "加载私钥失败\n");
        return 0;
    }

    printf("私钥加载成功\n");
    return 1;
}

/*
    测试sm2密钥对是否匹配成功
*/
static int test_sm2_keypair(SM2_KEY* key) {
    uint8_t message[] = "测试SM2密钥对";
    uint8_t signature[128] = { 0 };
    size_t siglen = 0;

    printf("测试密钥对：签名和验证...\n");
    uint8_t dgst[32];
    sm3_digest(message, strlen((char*)message), dgst);

    if (sm2_sign(key, dgst, signature, &siglen) != 1) {
        fprintf(stderr, "签名失败\n");
        return 0;
    }
    printf("签名成功，签名长度: %zu\n", siglen);

    if (sm2_verify(key, dgst, signature, siglen) != 1) {
        fprintf(stderr, "验证失败\n");
        return 0;
    }
    printf("验证成功，密钥对有效\n");

    return 1;
}

/*
    验签
    @param sm2_key: sm2密钥对
    @param dgst: 摘要值
    @param sig: 签名值
    @param siglen: 签名值长度
*/
static int test_verify_digest(SM2_KEY* sm2_key, const uint8_t* dgst, const uint8_t* sig, const size_t siglen) {
    //SM2_KEY sm2_key;
    SM2_KEY pub_key;
    //unsigned char dgst[32];
    //unsigned char sig[SM2_MAX_SIGNATURE_SIZE];
    //size_t siglen;
    int ret;

    /*sm3_digest((unsigned char*)"hello world", strlen("hello world"), dgst);
    format_bytes(stdout, 0, 0, "to be signed digest", dgst, sizeof(dgst));*/

    //sm2_key_generate(&sm2_key);

    //sm2_sign(&sm2_key, dgst, sig, &siglen);
    //format_bytes(stdout, 0, 0, "signature", sig, siglen);

    memcpy(&pub_key, sm2_key, sizeof(SM2_POINT));

    if ((ret = sm2_verify(&pub_key, dgst, sig, siglen)) != 1) {
        return 0;
    }
    return 1;

}

/*
    测试sm4 cbc 文件加密
    @param key: 对称加密密钥key
    @param iv: 初始化向量
    @param in_file: 输入文件
    @param out_file: 保存文件路径
*/
static int test_sm4_cbc_encrypt(const uint8_t* key, const uint8_t* iv, const char* in_file, const char* out_file) {
    SM4_CBC_CTX cbc_ctx;
    unsigned char inbuf[1024];
    unsigned char outbuf[1024 + 32];
    size_t inlen;
    size_t outlen;

    FILE* fp = fopen(in_file, "rb");
    if (!fp)
    {
        return 1;
    }

    FILE* fp2 = fopen(out_file, "wb");
    if (!fp2)
    {
        return 1;
    }

    if (sm4_cbc_encrypt_init(&cbc_ctx, key, iv) != 1) {
        fprintf(stderr, "%s %d: error\n", __FILE__, __LINE__);
        return 1;
    }
    while ((inlen = fread(inbuf, 1, sizeof(inbuf), fp)) > 0) {
        if (sm4_cbc_encrypt_update(&cbc_ctx, inbuf, inlen, outbuf, &outlen) != 1) {
            fprintf(stderr, "%s %d: error\n", __FILE__, __LINE__);
            return 1;
        }
        fwrite(outbuf, 1, outlen, fp2);
    }
    if (sm4_cbc_encrypt_finish(&cbc_ctx, outbuf, &outlen) != 1) {
        fprintf(stderr, "%s %d: error\n", __FILE__, __LINE__);
        return 1;
    }
    fwrite(outbuf, 1, outlen, fp2);
    fclose(fp);
    fclose(fp2);

    return 1;
}

/*
    测试sm4 cbc 文件解密
    @param key: 对称加密密钥key
    @param iv: 初始化向量
    @param in_file: 输入文件
    @param out_file: 保存文件路径
*/
static int test_sm4_cbc_decrypt(const uint8_t* key, const uint8_t* iv, const char* in_file, const char* out_file) {
    SM4_CBC_CTX cbc_ctx;
    unsigned char inbuf[1024];
    unsigned char outbuf[1024 + 32];
    size_t inlen;
    size_t outlen;


    FILE* fp = fopen(in_file, "rb");
    if (!fp)
    {
        return 1;
    }

    FILE* fp2 = fopen(out_file, "wb");
    if (!fp2)
    {
        return 1;
    }

    size_t total_encrypted = 0;

    fseek(fp, 0, SEEK_END);
    size_t max_encrypted_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    printf("\n解密文件大小: %.2f MB\n", max_encrypted_size / (1024.0 * 1024.0));
    printf("加密密钥: ");
    for (int i = 0; i < 16; i++) printf("%02x", key[i]);
    printf("\n");

    if (sm4_cbc_decrypt_init(&cbc_ctx, key, iv) != 1) {
        fprintf(stderr, "%s %d: error\n", __FILE__, __LINE__);
        return 1;
    }
    while ((inlen = fread(inbuf, 1, sizeof(inbuf), fp)) > 0) {
        if (sm4_cbc_decrypt_update(&cbc_ctx, inbuf, inlen, outbuf, &outlen) != 1) {
            fprintf(stderr, "%s %d: error\n", __FILE__, __LINE__);
            return 1;
        }
        fwrite(outbuf, 1, outlen, fp2);
        total_encrypted += outlen;
    }
    if (sm4_cbc_decrypt_finish(&cbc_ctx, outbuf, &outlen) != 1) {
        fprintf(stderr, "%s %d: error\n", __FILE__, __LINE__);
        return 1;
    }

    total_encrypted += outlen;
    fwrite(outbuf, 1, outlen, fp2);

    printf("文件解密完成，解密数据大小: %zu 字节\n", total_encrypted);
    fclose(fp2);
    fclose(fp);

    return 1;
}

/*
    测试生成P10证书
    @param p10_file: P10 证书保存路径
    @param key_file: 密钥对保存路径
*/
static int test_x509_req(const char* p10_file, const char* key_file)
{
    uint8_t subject[256];
    size_t subject_len;
    SM2_KEY sm2_key;
    uint8_t attrs[256];
    size_t attrs_len = 0;

    uint8_t req[512];
    uint8_t* p = req;
    size_t reqlen = 0;

    const char* pass = "123456";
    if (generate_sm2_keypai(key_file, pass)) {
        if (load_sm2_private_key(key_file, pass, &sm2_key)) {
            test_sm2_keypair(&sm2_key);
        }
    }

    /* int x509_name_set(uint8_t * d, size_t * dlen, size_t maxlen,
         const char country[2], const char* state, const char* locality,
         const char* org, const char* org_unit, const char* common_name);*/
    if (x509_name_set(subject, &subject_len, sizeof(subject), "CN", "Guangdong", "Shenzhen", "donsee", "donsee", "donsee") != 1
        || x509_req_sign_to_der(
            X509_version_v1, subject, subject_len, &sm2_key, attrs, attrs_len,
            OID_sm2sign_with_sm3, &sm2_key, SM2_DEFAULT_ID, strlen(SM2_DEFAULT_ID),
            &p, &reqlen) != 1) {
        error_print();
        return -1;
    }
    x509_req_print(stderr, 0, 0, "CertificationRequest", req, reqlen);
    FILE* fp;

    if ((fp = fopen("req.pem", "w")) == NULL) {
        error_print();
        return -1;
    }
    if (x509_req_to_pem(req, reqlen, fp) != 1) {
        error_print();
        return -1;
    }
    fclose(fp);
    x509_req_to_pem(req, reqlen, stderr);


    memset(req, 0, sizeof(req));

    if ((fp = fopen(p10_file, "r")) == NULL) {
        error_print();
        return -1;
    }
    if (x509_req_from_pem(req, &reqlen, sizeof(req), fp) != 1) {
        error_print();
        return -1;
    }
    if (x509_req_verify(req, reqlen, SM2_DEFAULT_ID, strlen(SM2_DEFAULT_ID)) != 1) {
        error_print();
        return -1;
    }
    format_print(stderr, 0, 0, "x509_req_verify() success\n");

    printf("%s() ok\n", __FUNCTION__);
    return 1;
}

/**
 * 加密文件并将加密数据准备为PKCS#7的enced_content
 * @param input_file: 输入文件路径
 * @param out_file: 输出加密后的文件
 * @param key: SM4密钥（16字节）
 * @param iv: 初始化向量（16字节）
 * @param enced_content: 输出的加密数据指针（需要调用者释放）
 * @param enced_content_len: 输出的加密数据长度
 * @return: 成功返回1，失败返回0
 */
int encrypt_file_to_enced_content(const char* input_file, const char* out_file,
    const uint8_t key[16], const uint8_t iv[16],
    uint8_t** enced_content, size_t* enced_content_len) {
    FILE* fp = NULL;
    FILE* fp_out = NULL;
    SM4_CBC_CTX ctx;
    uint8_t* encrypted_data = NULL;
    uint8_t buffer[64 * BUFFER_SIZE];
    uint8_t encrypted_buffer[64 * BUFFER_SIZE + 16];
    size_t bytes_read, encrypted_len;
    size_t total_encrypted = 0;
    size_t buffer_size = 64 * BUFFER_SIZE;
    size_t file_size = 0;
    int ret = 0;

    // 打开输入文件
    fp = fopen(input_file, "rb");
    if (!fp) {
        fprintf(stderr, "无法打开输入文件: %s\n", input_file);
        return 0;
    }

    fp_out = fopen(out_file, "wb");
    if (!fp_out) {
        fprintf(stderr, "无法创建输出文件: %s\n", out_file);
        fclose(fp);
        return 0;
    }

    // 获取文件大小（仅用于进度显示）
    fseek(fp, 0, SEEK_END);
    file_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    // 初始分配内存
    encrypted_data = (uint8_t*)malloc(buffer_size);
    if (!encrypted_data) {
        fprintf(stderr, "初始内存分配失败\n");
        fclose(fp);
        fclose(fp_out);
        return 0;
    }

    // 初始化SM4-CBC加密
    if (sm4_cbc_encrypt_init(&ctx, key, iv) != 1) {
        fprintf(stderr, "SM4加密初始化失败\n");
        fclose(fp);
        fclose(fp_out);
        free(encrypted_data);
        return 0;
    }

    printf("文件大小: %.2f MB\n", file_size / (1024.0 * 1024.0));
    printf("加密密钥: ");
    for (int i = 0; i < 16; i++) printf("%02x", key[i]);
    printf("\n");

    // 加密文件内容
    while ((bytes_read = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
        if (sm4_cbc_encrypt_update(&ctx, buffer, bytes_read, encrypted_buffer, &encrypted_len) != 1) {
            fprintf(stderr, "加密数据块失败\n");
            fclose(fp);
            fclose(fp_out);
            free(encrypted_data);
            return 0;
        }

        // 检查是否需要扩展内存
        if (total_encrypted + encrypted_len > buffer_size) {
            // 计算新的缓冲区大小（翻倍或按需扩展）
            size_t new_size;
            if (buffer_size < 1024 * 1024) {  // 小于1MB时翻倍
                new_size = buffer_size * 2;
            }
            else {  // 大于1MB时每次增加1MB
                new_size = buffer_size + 1024 * 1024;
            }

            // 确保新大小足够容纳当前数据
            if (new_size < total_encrypted + encrypted_len) {
                new_size = total_encrypted + encrypted_len + 1024 * 1024;
            }

            uint8_t* new_data = (uint8_t*)realloc(encrypted_data, new_size);
            if (!new_data) {
                fprintf(stderr, "内存扩展失败，当前已分配: %zu 字节\n", buffer_size);
                fclose(fp);
                fclose(fp_out);
                free(encrypted_data);
                return 0;
            }

            encrypted_data = new_data;
            buffer_size = new_size;
            printf("内存扩展至: %.2f MB\n", buffer_size / (1024.0 * 1024.0));
        }

        // 复制到输出缓冲区
        memcpy(encrypted_data + total_encrypted, encrypted_buffer, encrypted_len);
        total_encrypted += encrypted_len;

        // 写入输出文件
        fwrite(encrypted_buffer, 1, encrypted_len, fp_out);

        // 显示进度
        printf("\r加密进度: %.2f%%", (ftell(fp) * 100.0) / file_size);
        fflush(stdout);
    }

    // 完成加密（处理填充）
    if (sm4_cbc_encrypt_finish(&ctx, encrypted_buffer, &encrypted_len) != 1) {
        fprintf(stderr, "加密完成操作失败\n");
        fclose(fp);
        fclose(fp_out);
        free(encrypted_data);
        return 0;
    }

    if (encrypted_len > 0) {
        // 检查最终块是否需要扩展内存
        if (total_encrypted + encrypted_len > buffer_size) {
            size_t new_size = total_encrypted + encrypted_len + 1024;  // 额外1KB
            uint8_t* new_data = (uint8_t*)realloc(encrypted_data, new_size);
            if (!new_data) {
                fprintf(stderr, "最终内存扩展失败\n");
                fclose(fp);
                fclose(fp_out);
                free(encrypted_data);
                return 0;
            }
            encrypted_data = new_data;
            buffer_size = new_size;
        }

        memcpy(encrypted_data + total_encrypted, encrypted_buffer, encrypted_len);
        total_encrypted += encrypted_len;
        fwrite(encrypted_buffer, 1, encrypted_len, fp_out);
    }

    fclose(fp);
    fclose(fp_out);

    printf("\n文件加密完成，加密数据大小: %zu 字节\n", total_encrypted);
    printf("最终内存分配: %zu 字节\n", buffer_size);

    // 可选：缩小内存到实际使用大小
    if (total_encrypted < buffer_size) {
        uint8_t* trimmed_data = (uint8_t*)realloc(encrypted_data, total_encrypted);
        if (trimmed_data) {
            encrypted_data = trimmed_data;
            printf("内存优化至实际使用大小: %zu 字节\n", total_encrypted);
        }
    }

    *enced_content = encrypted_data;
    *enced_content_len = total_encrypted;

    return 1;
}

/*
    加密文件并封装p7证书
    @param in_file: 待加密的文件路径
    @param out_file: 加密后的文件路径
    @param encrypt_cert_file: 加密证书路径
    @param signature_cert_file: 签名证书路径
    @param sign_key_file: 私钥导出文件
*/
static int build_pkcs7_signed_and_enveloped_data(const char* in_file,
    const char* out_file,
    const char* encrypt_cert_file,
    const char* signature_cert_file,
    const char* sign_key_file,
    const char* encrypted_file,
    const char* decrypted_file
) {
    int ret = 0;
    uint8_t encrypt_cert_data[4096] = { 0 };
    size_t encrypt_cert_len = 0;

    // 加密证书中解析出来的数据
    int version;
    uint8_t* serial_number = NULL;
    size_t serial_number_len;
    int inner_signature_algor;
    uint8_t* issuer = NULL;
    size_t issuer_len;
    time_t not_before;
    time_t not_after;
    uint8_t* subject = NULL;
    size_t subject_len;
    SM2_KEY subject_public_key;
    uint8_t* issue_unique_id = NULL;
    size_t issue_unique_id_len;
    uint8_t* subject_unique_id = NULL;
    size_t subject_unique_id_len;
    uint8_t* exts = NULL;
    size_t exts_len;
    int signature_algor;
    uint8_t* signature = NULL;
    size_t signature_len;

    // 对称加密算法
    SM4_CBC_CTX cbc_ctx;

    // 签名证书pem数据
    uint8_t sig_cert_data[4096] = { 0 };
    size_t sig_cert_data_len = 0;

    uint8_t* recipient_info = NULL;
    uint8_t* encrypted_data = NULL;
    uint8_t* signer_info = NULL;

    // 加密数据缓冲区
    uint8_t* enced_content = NULL;
    size_t enced_content_len = 0;

    FILE* fp = NULL;

    // p7数据
    uint8_t* der_data = NULL;
    uint8_t* temp = NULL;
    size_t der_len = 0;

    uint8_t* q7_data = NULL;
    uint8_t* temp2 = NULL;
    size_t q7_data_len = 0;

    // 1. 获取加密证书详细信息
    /*
        Certificate  ::=  SEQUENCE  {
            tbsCertificate       TBSCertificate,
            signatureAlgorithm   AlgorithmIdentifier,
            signatureValue       BIT STRING }
    */
    if (!load_x509_cert_from_pem(
        encrypt_cert_file, 
        encrypt_cert_data,
        &encrypt_cert_len, 
        sizeof(encrypt_cert_data))) {
        fprintf(stderr, "加载加密证书失败\n");
        goto err;
    }

    // 2. 读取签名证书
    if (!load_x509_cert_from_pem(
        signature_cert_file, 
        sig_cert_data,
        &sig_cert_data_len,
        sizeof(sig_cert_data))) {
        fprintf(stderr, "加载加密证书失败\n");
        goto err;
    }

    // 3. 加载签名私钥
    fp = fopen(sign_key_file, "r");
    if (!fp) {
        fprintf(stderr, "无法打开签名私钥文件\n");
        goto err;
    }

    // 导出的私钥
    SM2_KEY sign_private_key;
    ret = sm2_private_key_info_decrypt_from_pem(&sign_private_key, "123456", fp);
    if (ret != 1) {
        fprintf(stderr, "导出密钥对成功\n");
        goto err;
    }
    fclose(fp);
    fp = NULL;

    printf("导出的私钥: ");
    for (int i = 0; i < 32; i++) {
        printf("%02x", sign_private_key.private_key[i]);
    }
    printf("\n");


    // 提取加密证书信息
    ret = x509_cert_get_details(
        encrypt_cert_data,                                       // 证书数据
        encrypt_cert_len,                                        // 证书长度
        &version,                                        // 证书版本
        (const uint8_t**)&serial_number,                 // 证书序列号
        &serial_number_len,                              // 证书序列号长度
        &inner_signature_algor,                          // 内部签名算法ID
        (const uint8_t**)&issuer,                        // 颁发者信息
        &issuer_len,                                     // 颁发者信息长度
        &not_before,                                     // 证书起始日期
        &not_after,                                      // 证书结束日期
        (const uint8_t**)&subject,                      // 证书主体信息
        &subject_len,                                    // 证书主体信息长度
        &subject_public_key,                             // 公钥信息
        (const uint8_t**)&issue_unique_id,             // 颁发者唯一ID
        &issue_unique_id_len,                            // 颁发者唯一ID长度
        (const uint8_t**)&subject_unique_id,           // 主体唯一ID
        &subject_unique_id_len,                          // 主体唯一ID长度
        (const uint8_t**)&exts,                         // 证书扩展数据
        &exts_len,                                       // 证书扩展数据长度
        &signature_algor,                                // 签名算法ID
        (const uint8_t**)&signature,                   // 签名数据
        &signature_len                                   // 签名数据长度
    );

    if (ret != 1) {
        fprintf(stderr, "获取证书信息失败\n");
        goto err;
    }

    // 对称加密密钥
    uint8_t symmetric_key[16];
    // 初始化向量
    uint8_t iv[16] = { 0 };

    rand_bytes(symmetric_key, sizeof(symmetric_key));
    rand_bytes(iv, sizeof(iv));

    printf("================文件加密及解密========================\n");

    if (encrypt_file_to_enced_content(in_file, 
        encrypted_file,
        symmetric_key, 
        iv,
        &enced_content,
        &enced_content_len)) {
        printf("加密文件成功...\n");
    }
    else {
        fprintf(stderr, "加密文件失败...\n");
    }

    // 测试解密是否成功
    if (test_sm4_cbc_decrypt(symmetric_key, iv, encrypted_file, decrypted_file)) {
        printf("文件解密成功...\n");
    }
    else {
        fprintf(stderr, "SM4 CBC 文件解密失败...\n");
    }

    printf("================构建接收者信息========================\n");

    // 4. 构建接收者信息（RecipientInfos）
    uint8_t recipient_infos[1024] = { 0 };
    size_t recipient_infos_len = 0;

    //int cms_recipient_infos_add_recipient_info(
    //    uint8_t * d, size_t * dlen, size_t maxlen,
    //    const SM2_KEY * public_key,
    //    const uint8_t * issuer, size_t issuer_len,
    //    const uint8_t * serial, size_t serial_len,
    //    const uint8_t * in, size_t inlen);

    // 使用接收者的公钥加密对称密钥key
    ret = cms_recipient_infos_add_recipient_info(
        recipient_infos, &recipient_infos_len, sizeof(recipient_infos),
        &subject_public_key,
        issuer, issuer_len,
        serial_number, serial_number_len,
        symmetric_key, sizeof(symmetric_key));

    if (ret != 1) {
        fprintf(stderr, "构建接收者信息失败\n");
        goto err;
    }

    // 5. 构建签名者信息（SignerInfos）
    printf("================计算文件摘要及验签========================\n");
    // 计算文件摘要
    fp = fopen(in_file, "rb");
    if (!fp) {
        fprintf(stderr, "读取待加密文件失败\n");
        goto err;
    }

    fseek(fp, 0, SEEK_END);
    size_t file_len = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    uint8_t signer_infos[1024] = { 0 };
    size_t signer_infos_len = 0;
    size_t bytes_read = 0;

    // 计算文件摘要
    SM3_CTX ctx;
    uint8_t digest[SM3_DIGEST_SIZE] = { 0 };

    // 一次读取64KB字节
    uint8_t buffer2[BUFFER_SIZE] = { 0 };

    // 将文件指针移动到开始处
    fseek(fp, 0, SEEK_SET);

    // 初始化SM3
    sm3_init(&ctx);

    // 读取输入文件并加密
    while ((bytes_read = fread(buffer2, 1, BUFFER_SIZE, fp)) > 0) {
        sm3_update(&ctx, buffer2, bytes_read);
    }

    // 计算最终摘要值
    sm3_finish(&ctx, digest);

    printf("SM3摘要后的数据: \n");
    for (int i = 0; i < sizeof(digest); i++) {
        printf("%02x", digest[i]);
    }
    printf("\n");

    fclose(fp);
    fp = NULL;

    uint8_t signature_value[256] = { 0 };
    size_t signature_value_len = 0;

    // 使用签名私钥对摘要进行签名
    // int sm2_sign(const SM2_KEY *key, const uint8_t dgst[32], uint8_t *sig, size_t *siglen);
    ret = sm2_sign(&sign_private_key, digest, signature_value, &signature_value_len);
    if (ret != 1) {
        fprintf(stderr, "SM2签名失败\n");
        goto err;
    }

    printf("SM3签名后的数据: \n");
    for (int i = 0; i < signature_value_len; i++) {
        printf("%02x", signature_value[i]);
    }
    printf("\n");

    // 验签
    if (test_verify_digest(&sign_private_key, digest, signature_value, signature_value_len)) {
        printf("验签成功...\n");
    }
    else {
        fprintf(stderr, "验签失败...\n");
    }

    printf("================构建签名者信息========================\n");
    const uint8_t* sign_issuer, * sign_serial;
    size_t sign_issuer_len, sign_serial_len;

    // 4. 提取加密证书信息
    ret = x509_cert_get_details(
        sig_cert_data,                                   // 签名证书数据
        sig_cert_data_len,                               // 签名证书长度
        &version,                                        // 证书版本
        (const uint8_t**)&sign_serial,                 // 证书序列号
        &sign_serial_len,                              // 证书序列号长度
        &inner_signature_algor,                          // 内部签名算法ID
        (const uint8_t**)&sign_issuer,                        // 颁发者信息
        &sign_issuer_len,                                     // 颁发者信息长度
        &not_before,                                     // 证书起始日期
        &not_after,                                      // 证书结束日期
        (const uint8_t**)&subject,                      // 证书主体信息
        &subject_len,                                    // 证书主体信息长度
        &subject_public_key,                             // 公钥信息
        (const uint8_t**)&issue_unique_id,              // 颁发者唯一ID
        &issue_unique_id_len,                            // 颁发者唯一ID长度
        (const uint8_t**)&subject_unique_id,             // 主体唯一ID
        &subject_unique_id_len,                          // 主体唯一ID长度
        (const uint8_t**)&exts,                          // 证书扩展数据
        &exts_len,                                       // 证书扩展数据长度
        &signature_algor,                                // 签名算法ID
        (const uint8_t**)&signature,                     // 签名数据
        &signature_len                                   // 签名数据长度
    );
    if (ret != 1) {
        fprintf(stderr, "获取证书信息失败\n");
        goto err;
    }

    /*
SignerInfos ::= SET OF SignerInfo;
*/
//int cms_signer_infos_add_signer_info(
//    uint8_t * d, size_t * dlen, size_t maxlen,
//    const SM3_CTX * sm3_ctx, const SM2_KEY * sign_key,
//    const uint8_t * issuer, size_t issuer_len,
//    const uint8_t * serial_number, size_t serial_number_len,
//    const uint8_t * authed_attrs, size_t authed_attrs_len,
//    const uint8_t * unauthed_attrs, size_t unauthed_attrs_len);
    ret = cms_signer_infos_add_signer_info(
        signer_infos, &signer_infos_len, sizeof(signer_infos),
        &ctx, &sign_private_key,
        sign_issuer, sign_issuer_len,           // 颁发者
        sign_serial, sign_serial_len,           // 序列号
        NULL, 0,
        NULL, 0);

    if (ret != 1) {
        fprintf(stderr, "构建签名者信息失败\n");
        goto err;
    }

    // 6. 构建证书集合（可选）
    // 这里按道理来说是 SET OF Certificate 集合，也就是  SET -> SEQUENCE，但是服务商只要求传入 SEQUENCE
    uint8_t certs[2028] = { 0 };
    uint8_t* cert_ptr = certs;
    size_t certificates_len = 0;

    ret = asn1_sequence_to_der(sig_cert_data, sig_cert_data_len,
        &cert_ptr, &certificates_len);
    if (ret != 1) {
        fprintf(stderr, "构建证书集合失败\n");
        goto err;
    }

    //uint8_t certs[2048] = { 0 };
    //uint8_t* certificates = certs;
    //size_t certificates_len = 0;

    //ret = asn1_set_to_der(certificate, cert_len, &certificates, &certificates_len);
    //if (ret != 1) {
    //    fprintf(stderr, "构建证书集合失败\n");
    //    goto err;
    //}

    // 
    FILE *fcerts = fopen("C:\\Users\\hp\\Desktop\\certs.dat", "wb");
    fwrite(certs, 1, certificates_len, fcerts);
    fclose(fcerts);

    printf("================构建P7========================\n");

#if 1
    int digest_algors[] = { OID_sm3 };  // 使用的摘要算法
    size_t digest_algors_cnt = 1;

    /*
SignedAndEnvelopedData ::= SEQUENCE {
    version			INTEGER (1),
    recipientInfos		SET OF RecipientInfo,
    digestAlgorithms	SET OF AlgorithmIdentifier,
    encryptedContentInfo	EncryptedContentInfo,
    certificates		[0] IMPLICIT SET OF Certificate OPTIONAL,
    crls			[1] IMPLICIT SET OF CertificateRevocationList OPTIONAL,
    signerInfos		SET OF SignerInfo }
*/
//int cms_signed_and_enveloped_data_to_der(
//    int version,
//    const uint8_t * rcpt_infos, size_t rcpt_infos_len,
//    const int* digest_algors, size_t digest_algors_cnt,
//    int content_type,
//    int enc_algor, const uint8_t * iv, size_t ivlen,
//    const uint8_t * enced_content, size_t enced_content_len,
//    const uint8_t * shared_info1, size_t shared_info1_len,
//    const uint8_t * shared_info2, size_t shared_info2_len,
//    const uint8_t * certs, size_t certs_len,
//    const uint8_t * crls, size_t crls_len,
//    const uint8_t * signer_infos, size_t signer_infos_len,
//    uint8_t * *out, size_t * outlen);
    ret = cms_signed_and_enveloped_data_to_der(
        1,
        recipient_infos, recipient_infos_len,               // 接受者信息
        digest_algors, digest_algors_cnt,                   // 摘要算法
        OID_cms_signed_and_enveloped_data,                  // 普通数据(content_type)
        OID_sm4_cbc,                                        // 对称加密算法 CBC
        iv, sizeof(iv),                                     // IV: 123456789123456
        enced_content, enced_content_len,                                 // 加密的内容,
        NULL, 0,                                            // 共享信息1
        NULL, 0,                                            // 共享信息2
        sig_cert_data, sig_cert_data_len,                   // 证书集合
        NULL, 0,                                            // CRL集合
        signer_infos, signer_infos_len,                     // 签名者信息,
        &der_data, &der_len);

    if (ret != 1) {
        fprintf(stderr, "创建p7失败\n");
        goto err;
    }

    der_data = (uint8_t*)malloc(der_len);
    if (!der_data) {
        fprintf(stderr, "为P7分配内存\n");
        goto err;
    }
    memset(der_data, 0, der_len);

    der_len = 0;
    ret = cms_signed_and_enveloped_data_to_der(
        1,
        recipient_infos, recipient_infos_len,               // 接受者信息
        digest_algors, digest_algors_cnt,                   // 摘要算法
        OID_cms_signed_and_enveloped_data,                  // 普通数据(content_type)
        OID_sm4_cbc,                                        // 对称加密算法 CBC
        iv, sizeof(iv),                                     // IV: 123456789123456
        enced_content, enced_content_len,                                 // 加密的内容,
        NULL, 0,                                            // 共享信息1
        NULL, 0,                                            // 共享信息2
        sig_cert_data, sig_cert_data_len,                   // 证书集合
        NULL, 0,                                            // CRL集合
        signer_infos, signer_infos_len,                     // 签名者信息,
        &der_data, &der_len);

    if (ret != 1 || !der_data) {
        fprintf(stderr, "创建p7失败\n");
        goto err;
    }

    temp = der_data - der_len;

    fp = fopen(out_file, "wb");
    if (!fp) {
        fprintf(stderr, "打开写文件失败\n");
        goto err;
    }

#if 1
    // 外部追加contentInfo
    /*int cms_content_info_to_der(
        int content_type,
        const uint8_t * content, size_t content_len,
        uint8_t * *out, size_t * outlen);*/
    ret = cms_content_info_to_der(
        OID_cms_signed_and_enveloped_data,
        temp, der_len,
        &q7_data,
        &q7_data_len);
    if (ret != 1) {
        fprintf(stderr, "创建q7失败\n");
        goto err;
    }

    q7_data = (uint8_t*)malloc(q7_data_len);
    if (!q7_data) {
        fprintf(stderr, "为Q7分配内存\n");
        goto err;
    }
    memset(q7_data, 0, q7_data_len);

    q7_data_len = 0;

    ret = cms_content_info_to_der(
        OID_cms_signed_and_enveloped_data,
        temp, der_len,
        &q7_data,
        &q7_data_len);
    if (ret != 1 || !q7_data) {
        fprintf(stderr, "创建q7失败\n");
        goto err;
    }

    temp2 = q7_data - q7_data_len;

    fwrite(temp2, 1, q7_data_len, fp);
    
#else
    fwrite(temp, 1, der_len, fp);
#endif  

    fclose(fp);
    fp = NULL;

    ret = 1;

#else
    // 使用CMS高级API生成完整的ContentInfo
    uint8_t* cms_data = NULL;
    size_t cms_len = 0;

    // 准备签名者信息
    CMS_CERTS_AND_KEY signer;
    signer.certs = sig_cert_data;
    signer.certs_len = sig_cert_data_len;
    signer.sign_key = &sign_private_key;

    // 准备接收者证书
    uint8_t rcpt_certs[4096];
    size_t rcpt_certs_len = 0;
    memcpy(rcpt_certs, encrypt_cert_data, encrypt_cert_len);
    rcpt_certs_len = encrypt_cert_len;


    // 读取要加密的内容
    FILE* content_fp = fopen(in_file, "rb");
    if (!content_fp) {
        fprintf(stderr, "无法打开输入文件: %s\n", in_file);
        goto err;
    }

    fseek(content_fp, 0, SEEK_END);
    size_t content_len = ftell(content_fp);
    fseek(content_fp, 0, SEEK_SET);

    uint8_t* content_data = malloc(content_len);
    if (!content_data) {
        fprintf(stderr, "内存分配失败\n");
        fclose(content_fp);
        goto err;
    }

    if (fread(content_data, 1, content_len, content_fp) != content_len) {
        fprintf(stderr, "读取文件内容失败\n");
        fclose(content_fp);
        free(content_data);
        goto err;
    }
    fclose(content_fp);

    // 使用CMS高级API生成SignedAndEnvelopedData
    ret = cms_sign_and_envelop(
        NULL, &cms_len,                    // 第一次调用获取长度
        &signer, 1,                        // 签名者
        rcpt_certs, rcpt_certs_len,        // 接收者证书
        OID_sm4_cbc,                       // 加密算法
        symmetric_key, sizeof(symmetric_key), // 对称密钥
        iv, sizeof(iv),                    // IV
        OID_cms_data,                      // 内容类型
        content_data, content_len,         // 要保护的数据
        NULL, 0,                           // CRLs
        NULL, 0,                           // shared_info1
        NULL, 0                            // shared_info2
    );

    if (ret != 1) {
        fprintf(stderr, "计算CMS长度失败\n");
        free(content_data);
        goto err;
    }

    // 分配内存并生成CMS数据
    cms_data = malloc(cms_len);
    if (!cms_data) {
        fprintf(stderr, "内存分配失败\n");
        free(content_data);
        goto err;
    }

    ret = cms_sign_and_envelop(
        cms_data, &cms_len,                // 输出缓冲区
        &signer, 1,                        // 签名者
        rcpt_certs, rcpt_certs_len,        // 接收者证书
        OID_sm4_cbc,                       // 加密算法
        symmetric_key, sizeof(symmetric_key), // 对称密钥
        iv, sizeof(iv),                    // IV
        OID_cms_data,                      // 内容类型
        content_data, content_len,         // 要保护的数据
        NULL, 0,                           // CRLs
        NULL, 0,                           // shared_info1
        NULL, 0                            // shared_info2
    );

    free(content_data);

    if (ret != 1) {
        fprintf(stderr, "生成CMS数据失败\n");
        goto err;
    }

    // 写入文件
    fp = fopen(out_file, "wb");
    if (!fp) {
        fprintf(stderr, "无法创建输出文件: %s\n", out_file);
        goto err;
    }

    if (fwrite(cms_data, 1, cms_len, fp) != cms_len) {
        fprintf(stderr, "写入文件失败\n");
        fclose(fp);
        goto err;
    }

    fclose(fp);
    printf("P7文件生成成功，大小: %zu 字节\n", cms_len);
#endif

err:
    if (fp) {
        fclose(fp);
        fp = NULL;
    }

    if (recipient_info) {
        free(recipient_info);
        recipient_info = NULL;
    }

    if (encrypted_data) {
        free(encrypted_data);
        encrypted_data = NULL;
    }

    if (signer_info) {
        free(signer_info);
        signer_info = NULL;
    }

    if (enced_content) {
        free(enced_content);
        enced_content = NULL;
    }

    if (temp) {
        free(temp);
        temp = NULL;
    }

    if (temp2) {
        free(temp2);
        temp2 = NULL;
    }

    return ret;
}

/*
* 测试加密证书，的公钥加密，私钥解密
* @param encrypt_cert_file 加密证书
* @param key_file 私钥文件路径
*
*/
static int test_encryp_cert(const char* encrypt_cert_file, const char* key_file) {
    uint8_t cert_data[1024] = { 0 };
    size_t cert_data_len = 0;
    if (!load_x509_cert_from_pem(encrypt_cert_file, cert_data, &cert_data_len, sizeof(cert_data))) {
        fprintf(stderr, "加载加密证书失败");
        return 0;
    }

    // 加密证书中解析出来的数据
    int version;
    uint8_t* serial_number = NULL;
    size_t serial_number_len;
    int inner_signature_algor;
    uint8_t* issuer = NULL;
    size_t issuer_len;
    time_t not_before;
    time_t not_after;
    uint8_t* subject = NULL;
    size_t subject_len;
    SM2_KEY subject_public_key;
    uint8_t* issue_unique_id = NULL;
    size_t issue_unique_id_len;
    uint8_t* subject_unique_id = NULL;
    size_t subject_unique_id_len;
    uint8_t* exts = NULL;
    size_t exts_len;
    int signature_algor;
    uint8_t* signature = NULL;
    size_t signature_len;

    // 提取加密证书信息
    int ret = x509_cert_get_details(
        cert_data,                                       // 证书数据
        cert_data_len,                                        // 证书长度
        &version,                                        // 证书版本
        (const uint8_t**)&serial_number,                 // 证书序列号
        &serial_number_len,                              // 证书序列号长度
        &inner_signature_algor,                          // 内部签名算法ID
        (const uint8_t**)&issuer,                        // 颁发者信息
        &issuer_len,                                     // 颁发者信息长度
        &not_before,                                     // 证书起始日期
        &not_after,                                      // 证书结束日期
        (const uint8_t**)&subject,                      // 证书主体信息
        &subject_len,                                    // 证书主体信息长度
        &subject_public_key,                             // 公钥信息
        (const uint8_t**)&issue_unique_id,             // 颁发者唯一ID
        &issue_unique_id_len,                            // 颁发者唯一ID长度
        (const uint8_t**)&subject_unique_id,           // 主体唯一ID
        &subject_unique_id_len,                          // 主体唯一ID长度
        (const uint8_t**)&exts,                         // 证书扩展数据
        &exts_len,                                       // 证书扩展数据长度
        &signature_algor,                                // 签名算法ID
        (const uint8_t**)&signature,                   // 签名数据
        &signature_len                                   // 签名数据长度
    );

    if (ret != 1) {
        fprintf(stderr, "获取证书信息失败\n");
        return 0;
    }

    FILE* fp = fopen(key_file, "r");
    if (!fp) {
        fprintf(stderr, "打开私钥文件失败\n");
        return 0;
    }
    /*SM2_KEY private_key;
    ret = sm2_private_key_info_decrypt_from_pem(&private_key, "12345678", fp);
    if (ret != 1) {
        fprintf(stderr, "导出私钥失败\n");
        return 0;
    }
    fclose(fp);
    fp = NULL;*/

    const uint8_t private_key[32] = { 0xa9, 0x7c, 0x13, 0x11, 0x14, 0xd4, 0x41, 0xf4, 0xbf, 0x15,
        0x55, 0xd5, 0x20, 0x17, 0x33, 0x77, 0xa6, 0x28, 0x56, 0xee, 0x20, 0x87, 0xa7, 0x51, 0x4e, 0x99, 0x36, 0x66, 0x75,
        0xe2,0xa5, 0x52 };

    SM2_KEY sm2_key;
    // 使用 sm2_key_set_private_key 加载私钥文件
    sm2_key_set_private_key(&sm2_key, (const uint8_t*)&private_key);

    uint8_t symmetric_key[16] = { 0 }; // 假设对称密钥是16字节
    uint8_t encrypted_key[256] = { 0 };
    size_t encrypted_key_len = 0;
    uint8_t decrypted_key[16] = { 0 };
    size_t decrypted_key_len = 0;

    // 生成随机对称密钥
    rand_bytes(symmetric_key, sizeof(symmetric_key));

    // 使用公钥加密对称密钥（模拟函数内部操作）
    if (sm2_encrypt(&subject_public_key, symmetric_key, sizeof(symmetric_key), encrypted_key, &encrypted_key_len) != 1) {
        fprintf(stderr, "加密对称密钥失败\n");
        return 0;
    }

    // 使用私钥解密加密的对称密钥
    if (sm2_decrypt(&sm2_key, encrypted_key, encrypted_key_len, decrypted_key, &decrypted_key_len) != 1) {
        fprintf(stderr, "解密对称密钥失败\n");
        return 0;
    }

    // 比较解密后的对称密钥和原始对称密钥
    if (decrypted_key_len != sizeof(symmetric_key) || memcmp(decrypted_key, symmetric_key, sizeof(symmetric_key)) != 0) {
        fprintf(stderr, "解密后的对称密钥与原始密钥不匹配\n");
        return 0;
    }

    printf("验证成功...\n");

    return 1;
}


/*
 * 解密PKCS#7 SignedAndEnvelopedData格式的文件
 * @param p7_file: 待解密的P7文件路径
 * @param out_file: 解密后生成的文件路径
 * @param key_file: 私钥文件路径（PEM格式）
 * @param pass: 解析私钥文件的密码
 * @return: 成功返回1，失败返回0
 */
static int decrypt_pkcs7_signed_and_enveloped_data(const char* p7_file, const char* out_file,
    const char* key_file, const char* pass) {
    int ret = 0;
    FILE* fp = NULL;
    uint8_t* original_p7_data = NULL;  // 保存原始指针用于释放
    uint8_t* p7_data = NULL;           // 用于解析的指针
    size_t p7_data_len = 0;
    uint8_t* decrypted_content = NULL;
    size_t decrypted_content_len = 0;

    printf("开始解密P7文件: %s\n", p7_file);

    // 1. 读取P7文件内容
    fp = fopen(p7_file, "rb");
    if (!fp) {
        fprintf(stderr, "无法打开P7文件: %s\n", p7_file);
        goto err;
    }

    fseek(fp, 0, SEEK_END);
    p7_data_len = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    original_p7_data = (uint8_t*)malloc(p7_data_len);  // 保存原始指针
    if (!original_p7_data) {
        fprintf(stderr, "内存分配失败\n");
        goto err;
    }

    p7_data = original_p7_data;  // 解析指针指向同一内存

    if (fread(p7_data, 1, p7_data_len, fp) != p7_data_len) {
        fprintf(stderr, "读取P7文件失败\n");
        goto err;
    }
    fclose(fp);
    fp = NULL;

    printf("P7文件大小: %zu 字节\n", p7_data_len);

#if 1
    uint8_t* m_content = NULL;
    size_t m_content_len = 0;
    int m_content_type = 0;

    size_t m_data_len = p7_data_len;

    printf("OID_cms_signed_and_enveloped_data: %d\n", OID_cms_signed_and_enveloped_data);
    ret = cms_content_info_from_der(
        &m_content_type,
        (const uint8_t**)&m_content, &m_content_len,
        (const uint8_t**)&p7_data, &m_data_len);
    if (ret != 1) {
        fprintf(stderr, "无法解开content\n");
        goto err;
    }

    printf("m_content_type: %d\n", m_content_type);
    FILE* ff = fopen("D:\\mywork\\C++\\Demo\\GmSSLDemo\\Debug\\content.dat", "wb");
    if (ff) {
        fwrite(m_content, 1, m_content_len, ff);
        fclose(ff);
    }

#endif
    // 2. 加载私钥
    SM2_KEY private_key;
    FILE* key_fp = fopen(key_file, "r");
    if (!key_fp) {
        fprintf(stderr, "无法打开私钥文件: %s\n", key_file);
        goto err;
    }

    //ret = sm2_private_key_info_decrypt_from_pem(&private_key, pass, key_fp);
    //fclose(key_fp);
    //if (ret != 1) {
    //    fprintf(stderr, "加载私钥失败，请检查密码是否正确\n");
    //    goto err;
    //}
    //printf("私钥加载成功\n");

  /*  const uint8_t private_key_self[32] = {0xb4, 0x5e, 0x56, 0xa8, 0x8e, 0xd7, 0x1f, 0x49,
        0x51, 0x8b, 0xdc, 0x69, 0x0d, 0xe4, 0x9f, 0xe0, 0xdd, 0x74, 0xcb, 0xbd, 0x9e, 0x1e, 0x00, 0x06,
        0xf4, 0x3b, 0x45, 0x4f, 0x0f, 0x5f, 0x8d, 0xda };
    sm2_key_set_private_key(&private_key, (const uint8_t*)&private_key_self);*/

    uint8_t private_key_data[32] = { 0 };
    if (parse_key_pem(key_file, private_key_data) != 1) {
        fprintf(stderr, "解析私钥证书失败!\n");
        goto err;
    }
    sm2_key_set_private_key(&private_key, (const uint8_t*)&private_key_data);

    // 3. 首先解析ContentInfo
    uint8_t* p = NULL;
    p = m_content;
    size_t len = m_content_len;

    int content_type;
    const uint8_t* content = NULL;
    size_t content_len = 0;

    // 4. 现在解析SignedAndEnvelopedData
    const uint8_t* signed_env_data = content;
    size_t signed_env_len = content_len;

    int version;
    const uint8_t* recipient_infos;
    size_t recipient_infos_len;
    int digest_algors[4];
    size_t digest_algors_cnt = 4;
    const uint8_t* enced_content_info;
    size_t enced_content_info_len;
    const uint8_t* certificates;
    size_t certificates_len;
    const uint8_t* crls;
    size_t crls_len;
    const uint8_t* signer_infos;
    size_t signer_infos_len;

    ret = cms_signed_and_enveloped_data_from_der(
        &version,
        &recipient_infos, &recipient_infos_len,
        digest_algors, &digest_algors_cnt, 4,
        &enced_content_info, &enced_content_info_len,
        &certificates, &certificates_len,
        &crls, &crls_len,
        &signer_infos, &signer_infos_len,
        &m_content, &m_content_len);

    if (ret != 1) {
        fprintf(stderr, "解析SignedAndEnvelopedData结构失败\n");
        goto err;
    }

    printf("解析SignedAndEnvelopedData成功:\n");
    printf("  Version: %d\n", version);
    printf("  摘要算法数量: %zu\n", digest_algors_cnt);
    printf("  接收者信息长度: %zu\n", recipient_infos_len);
    printf("  加密内容信息长度: %zu\n", enced_content_info_len);

    // 5. 解析EncryptedContentInfo获取加密内容和算法参数
    const uint8_t* content_info_ptr = enced_content_info;
    size_t content_info_len = enced_content_info_len;

    int enc_content_type;
    int enc_algor;
    const uint8_t* enc_iv;
    size_t enc_iv_len;
    const uint8_t* enced_content;
    size_t enced_content_len;
    const uint8_t* shared_info1;
    size_t shared_info1_len;
    const uint8_t* shared_info2;
    size_t shared_info2_len;

    ret = cms_enced_content_info_from_der(
        &enc_content_type,
        &enc_algor, &enc_iv, &enc_iv_len,
        &enced_content, &enced_content_len,
        &shared_info1, &shared_info1_len,
        &shared_info2, &shared_info2_len,
        &content_info_ptr, &content_info_len);

    if (ret != 1) {
        fprintf(stderr, "解析加密内容信息失败\n");
        goto err;
    }

    printf("  内容类型: %s\n", cms_content_type_name(enc_content_type));
    printf("  加密算法: %d\n", enc_algor);
    printf("  IV长度: %zu\n", enc_iv_len);
    printf("  加密内容长度: %zu\n", enced_content_len);

    // 6. 解密对称密钥
    uint8_t symmetric_key[16] = { 0 };
    size_t symmetric_key_len = 0;

    // 遍历RecipientInfos找到对应的接收者信息
    int found_key = 0;

    // 遍历每个RecipientInfo
    const uint8_t* rcpt_ptr = NULL;
    size_t rcpt_remaining = recipient_infos_len;

    while (rcpt_remaining > 0) {
        int rcpt_version;
        const uint8_t* issuer;
        size_t issuer_len;
        const uint8_t* serial_number;
        size_t serial_number_len;
        int pke_algor;
        const uint8_t* params;
        size_t params_len;
        const uint8_t* enced_key;
        size_t enced_key_len;

        const uint8_t* temp_ptr = recipient_infos;
        size_t temp_remaining = rcpt_remaining;

        // 解析RecipientInfo
        ret = cms_recipient_info_from_der(
            &rcpt_version,
            &issuer, &issuer_len,
            &serial_number, &serial_number_len,
            &pke_algor, &params, &params_len,
            &enced_key, &enced_key_len,
            &temp_ptr, &temp_remaining);

        if (ret != 1) {
            fprintf(stderr, "解析RecipientInfo失败\n");
            break;
        }

        printf("尝试解密RecipientInfo: issuer_len=%zu, serial_len=%zu\n",
            issuer_len, serial_number_len);

        // 重置指针回到当前RecipientInfo的开始
        const uint8_t* current_rcpt = recipient_infos;
        size_t current_remaining = rcpt_remaining;

        // 尝试使用私钥解密对称密钥
        ret = cms_recipient_info_decrypt_from_der(
            &private_key,
            issuer, issuer_len,
            serial_number, serial_number_len,
            symmetric_key, &symmetric_key_len, sizeof(symmetric_key),
            &current_rcpt, &current_remaining);

        if (ret == 1) {
            printf("对称密钥解密成功\n");
            printf("对称密钥: ");
            for (int i = 0; i < symmetric_key_len; i++) {
                printf("%02x", symmetric_key[i]);
            }
            printf("\n");
            found_key = 1;
            break;
        }

        // 移动到下一个RecipientInfo
        rcpt_ptr = temp_ptr;
        rcpt_remaining = temp_remaining;
    }

    if (!found_key) {
        fprintf(stderr, "无法解密对称密钥\n");
        goto err;
    }

    // 7. 使用对称密钥解密内容
    printf("开始解密内容...\n");

    // 使用SM4-CBC解密 - 使用从文件中解析的IV
    SM4_CBC_CTX decrypt_ctx;
    uint8_t* temp_buffer = (uint8_t*)malloc(enced_content_len + 16);
    if (!temp_buffer) {
        fprintf(stderr, "内存分配失败\n");
        goto err;
    }

    size_t total_decrypted = 0;

    // 初始化解密上下文 - 使用从文件中解析的IV
    if (sm4_cbc_decrypt_init(&decrypt_ctx, symmetric_key, enc_iv) != 1) {
        fprintf(stderr, "解密初始化失败\n");
        free(temp_buffer);
        goto err;
    }

    // 处理加密数据
    size_t update_len, finish_len;
    if (sm4_cbc_decrypt_update(&decrypt_ctx, enced_content, enced_content_len, temp_buffer, &update_len) != 1) {
        fprintf(stderr, "解密更新失败\n");
        free(temp_buffer);
        goto err;
    }
    total_decrypted += update_len;

    if (sm4_cbc_decrypt_finish(&decrypt_ctx, temp_buffer + update_len, &finish_len) != 1) {
        fprintf(stderr, "解密完成失败\n");
        free(temp_buffer);
        goto err;
    }
    total_decrypted += finish_len;

    // 分配解密内容缓冲区
    decrypted_content = (uint8_t*)malloc(total_decrypted);
    if (!decrypted_content) {
        fprintf(stderr, "内存分配失败\n");
        free(temp_buffer);
        goto err;
    }

    // 合并解密数据
    memcpy(decrypted_content, temp_buffer, update_len);
    memcpy(decrypted_content + update_len, temp_buffer + update_len, finish_len);
    decrypted_content_len = total_decrypted;

    free(temp_buffer);

    printf("解密内容大小: %zu 字节\n", decrypted_content_len);

    // 8. 保存解密后的内容到文件
    fp = fopen(out_file, "wb");
    if (!fp) {
        fprintf(stderr, "无法创建输出文件: %s\n", out_file);
        goto err;
    }

    if (fwrite(decrypted_content, 1, decrypted_content_len, fp) != decrypted_content_len) {
        fprintf(stderr, "写入输出文件失败\n");
        fclose(fp);
        goto err;
    }
    fclose(fp);
    fp = NULL;

    printf("解密成功！解密文件已保存到: %s\n", out_file);

    ret = 1;

err:
    if (fp) fclose(fp);
    if (original_p7_data) free(original_p7_data);
    if (decrypted_content) free(decrypted_content);

    return ret;
}

int main(int argc, char* argv[]) {

    if (argc < 2) {
        printf("用法:\n");
        printf("  %s p10 <P10证书路径> <密钥对文件路径>\n", argv[0]);
        printf("  %s p7 <输入文件> <输出文件> <加密证书文件> <签名证书文件> <用户密钥文件> <加密后文件> <解密后文件>\n", argv[0]);
        printf("  %s encrypt_valid <加密证书路径> <私钥文件路径>\n", argv[0]);
        printf("  %s p7d <待解密P7文件> <解密输出文件>  <私钥文件>  <私钥密码>\n", argv[0]);
        return 1;
    }

    if (strcmp(argv[1], "p10") == 0) {
        if (argc != 4) {
            printf("用法: %s p10 <P10证书路径> <密钥对文件路径>\n", argv[0]);
            return 1;
        }
        return test_x509_req(argv[2], argv[3]);
    }
    else if (strcmp(argv[1], "p7") == 0) {
        if (argc != 9) {
            printf("用法: %s p7 <输入文件> <输出文件> <加密证书文件> <签名证书文件> <用户密钥文件> <加密后文件>  <解密后文件>\n", argv[0]);
            return 1;
        }
        return build_pkcs7_signed_and_enveloped_data(argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
    }
    else if (strcmp(argv[1], "encrypt_valid") == 0) {
        if (argc != 4) {
            printf("用法: %s encrypt_valid <加密证书路径> <私钥文件路径>\n", argv[0]);
            return 1;
        }
        return test_encryp_cert(argv[2], argv[3]);
    }
    else if (strcmp(argv[1], "p7d") == 0) {
        if (argc != 6) {
            printf("用法: %s p7d <待解密P7文件> <解密输出文件>  <私钥文件>  <私钥密码>\n", argv[0]);
            return 1;
        }
        return decrypt_pkcs7_signed_and_enveloped_data(argv[2], argv[3], argv[4], argv[5]);
    } 
    else {
        printf("未知命令: %s\n", argv[1]);
        return 1;
    }
}